/**
 * Created with CLion.
 * Description: 
 * User: loong
 * Date: 2025/4/22
 * Time: 22:44
 */

#include "Scene.h"
#include "ObjectScreen.h"
#include "ObjectWorld.h"

void Scene::Init()
{
    Object::Init();
    for(auto & child : children_world_) {
        child->Init();
    }
    for(auto & child : children_screen_) {
        child->Init();
    }
}

void Scene::Update(float _dt)
{
    Object::Update(_dt);
    auto world_itor = children_world_.begin();
    while(world_itor != children_world_.end()) {
        auto child = *world_itor;
        if(child->NeedRemove()) {
            world_itor = children_world_.erase(world_itor);
            child->Clean();
            delete child;
            child = nullptr;
        }
        else {
            if(child->IsActive())
                child->Update(_dt);
            ++world_itor;
        }
    }

    auto screen_itor = children_screen_.begin();
    while(screen_itor != children_screen_.end()) {
        auto child = *screen_itor;
        if(child->NeedRemove()) {
            screen_itor = children_screen_.erase(screen_itor);
            child->Clean();
            delete child;
            child = nullptr;
        }
        else {
            if(child->IsActive())
                child->Update(_dt);
            ++screen_itor;
        }
    }
}

void Scene::Render()
{
    Object::Render();
    for(auto & child : children_world_) {
        if(child->IsActive())
            child->Render();
    }
    for(auto & child : children_screen_) {
        if(child->IsActive())
            child->Render();
    }
}

void Scene::Clean()
{
    Object::Clean();
    for(auto & child : children_world_) {
        child->Clean();
    }
    children_world_.clear();
    for(auto & child : children_screen_) {
        child->Clean();
    }
    children_screen_.clear();
    Object::Clean();
}

void Scene::HandleEvent(SDL_Event & _event)
{
    Object::HandleEvent(_event);
    for(auto & child : children_screen_) {
        if(child->IsActive())
            child->HandleEvent(_event);
    }
    for(auto & child : children_world_) {
        if(child->IsActive())
            child->HandleEvent(_event);
    }
}

void Scene::AddChild(Object * child)
{
    switch(child->GetType()) {
        case ObjectType::OBJECT_WORLD:
        case ObjectType::ENEMY:
            children_world_.emplace_back(dynamic_cast<ObjectWorld *>(child));
            break;
        case ObjectType::OBJECT_SCREEN:
            children_screen_.emplace_back(dynamic_cast<ObjectScreen *>(child));
            break;
        default:
            children_.emplace_back(child);
            break;
    }
}

void Scene::RemoveChild(Object * child)
{
    switch(child->GetType()) {
        case ObjectType::OBJECT_WORLD:
        case ObjectType::ENEMY:
            children_world_.erase(std::remove(children_world_.begin(), children_world_.end(), dynamic_cast<ObjectWorld *>(child)), children_world_.end());
            break;
        case ObjectType::OBJECT_SCREEN:
            children_screen_.erase(std::remove(children_screen_.begin(), children_screen_.end(), dynamic_cast<ObjectScreen *>(child)), children_screen_.end());
            break;
        default:
            children_.erase(std::remove(children_.begin(), children_.end(), child), children_.end());
            break;
    }
}

void Scene::SetCameraPosition(const glm::vec2 & _camera_position)
{
    camera_position_ = _camera_position;
    camera_position_ = clamp(camera_position_, glm::vec2 {-30}, world_size_ - game_.GetScreenSize() + glm::vec2 {30});
}